package it.softphone.cmc.impl;

import it.softphone.cmc.CMCServiceManager;
import it.softphone.cmc.CMCServiceManager.JerseyCall;
import it.softphone.cmc.server.service.ScriptletManagerService;
import it.softphone.cmc.shared.entity.Asset;
import it.softphone.cmc.shared.entity.AssetImpl;
import it.softphone.cmc.shared.entity.ScriptletAsset;
import it.softphone.commons.json.server.JSONException;
import it.softphone.commons.json.server.JSONObject;
import it.softphone.commons.service.LogAware;
import it.softphone.commons.util.Util;

import java.util.List;

import javax.script.ScriptException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;


import com.google.web.bindery.autobean.shared.AutoBean;
import com.google.web.bindery.autobean.shared.AutoBeanCodex;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.MultivaluedMapImpl;

/**
 * 
 * @author softphone
 *
 */
public class ScriptletServiceClientImpl implements ScriptletManagerService , LogAware {

	private static final String REDIRECT_URI 					= "redirect_uri";
	private static final String SCRIPTLET_BASEURI 				= "scriptlet";
	private static final String SCRIPTLET_KEYS_BASEURI 			= SCRIPTLET_BASEURI + "/keys";
	private static final String SCRIPTLET_EXEC_BASEURI 			= "exec/";
	private static final String SCRIPTLET_EXEC_BASEURI_ASYNC	= SCRIPTLET_EXEC_BASEURI + "async:";
	
	final private CMCServiceManager manager;
	
	
	public ScriptletServiceClientImpl(CMCServiceManager manager) {
		super();
		this.manager = manager;
	}

	public final Asset makeAsset() {
		return manager.ef.makeAsset().as();
	}
	
	@Override
	public ScriptletAsset makeScriptlet() {
		return manager.ef.makeScriptlet().as();
	}

	@Override
	public ScriptletAsset makeScriptletFromJson(JSONObject object) 	throws JSONException {
		
		AutoBean<ScriptletAsset> aa = AutoBeanCodex.decode(manager.ef, ScriptletAsset.class, object.toString());

		return aa.as();
	}
	
	public ScriptletAsset makeAssetFromResource( Asset asset, String type, String resource ) throws Exception {
		
		java.io.InputStream is =  getClass().getClassLoader().getResourceAsStream(resource);
		
		return makeAssetFromReader( asset, type, new java.io.InputStreamReader(is) );
	}

	public ScriptletAsset makeAssetFromFile( Asset asset, String type, java.io.File f ) throws Exception {
		
		return makeAssetFromReader( asset, type, new java.io.FileReader(f) );
		
	}
	
	public ScriptletAsset makeAssetFromReader( Asset asset, String type, java.io.Reader reader ) throws Exception {
		
		final String content = Util.toString( reader );

		ScriptletAsset a = makeScriptlet();
		
		a.setGroupId( asset.getGroupId() );
		a.setArtifactId( asset.getArtifactId() );
		a.setVersion( asset.getVersion() );
		a.setType(type);
		a.setContent(content);
		
		return a;
		
	}

	@Override
	public void saveScriptlet(final ScriptletAsset s) {
		
		manager.call( new JerseyCall<String>() {

			@Override
			public String exec() {
				
				MultivaluedMap<String, String> params = new MultivaluedMapImpl();
				params.putSingle("asset", new JSONObject(s).toString() );
				
				return manager.getClient().resource( manager.getServiceUrl(SCRIPTLET_BASEURI))
										.type(MediaType.APPLICATION_FORM_URLENCODED)
										.post(String.class, params);
				
			}
			
		});

	}

	@Override
	public ScriptletAsset findScriptletByKey( final String key) {
		String result = findScriptletByKeyAsJSON(key);
		
		AutoBean<ScriptletAsset> aa = AutoBeanCodex.decode(manager.ef, ScriptletAsset.class, result);

		return aa.as();
	}

	private String findScriptletByKeyAsJSON( final String key) {
		if( manager.getClient() == null ) throw new IllegalStateException("service has not been initialized!!");

		return manager.call( new JerseyCall<String>() {

			@Override
			public String exec() {
				
				String result = manager.getClient().resource(manager.getServiceUrl(SCRIPTLET_BASEURI) )
						.queryParam("key", key)
						.get(String.class);
				
				return result;
				
			}
		});
	}

	@Override
	public List<String> findScriptletKeys( final Asset filter) {
		if( manager.getClient() == null ) throw new IllegalStateException("service has not been initialized!!");

		// Doesn't work
		//AutoBean<Asset> bean = AutoBeanUtils.getAutoBean(filter);
		//final String param = AutoBeanCodex.encode(bean).getPayload();
		
		java.util.List<String> result = manager.call( new JerseyCall<java.util.List<String>>() {

			@Override
			public java.util.List<String> exec() {
				String result = manager.getClient().resource(manager.getServiceUrl( SCRIPTLET_KEYS_BASEURI ) )
						.queryParam("asset", new it.softphone.commons.json.server.JSONObject(filter).toString())
						.get(String.class);

				AutoBean<ScriptletAsset.KeyResulSet> aa = AutoBeanCodex.decode(manager.ef, ScriptletAsset.KeyResulSet.class, result);
				
				return aa.as().getResult();
				
			}
		});

		return result;
	}


	@Override
	public Object execScriptlet( final ScriptletAsset s, final Object... args) throws ScriptException, NoSuchMethodException {
		if( manager.getClient() == null ) throw new IllegalStateException("service has not been initialized!!");

		return manager.call( new JerseyCall<String>() {

			@Override
			public String exec() {

				WebResource res = manager.getClient()
									.resource( manager.getServiceUrl(SCRIPTLET_EXEC_BASEURI + AssetImpl.toKey(s)) );
									
				if( args!=null ) {
					for( Object arg : args ) {
						res.queryParam("arg", String.valueOf(arg) );
					}
				}
				
				return res.get(String.class);
				
			}
		});
	}
	
	
	/**
	 * 
	 * @param script
	 * @param param
	 * @throws Exception
	 */
	public String execScriptGet( final Asset asset, final MultivaluedMap<String,String> queryData ) throws Exception {		
		if( manager.getClient() == null ) throw new IllegalStateException("service has not been initialized!!");

		return manager.call( new JerseyCall<String>() {

			@Override
			public String exec() {

				return  manager.getClient()
									.resource( manager.getServiceUrl(SCRIPTLET_EXEC_BASEURI + AssetImpl.toKey(asset)) )
									.queryParams(queryData)
									.get(String.class);
				
			}
		});
		
	}
	
	/**
	 * 
     *				
	 *	MultivaluedMap<String,String> formData = new MultivaluedMapImpl();
	 *	formData.add("json", 
	 *					"{\"records\":[{\"COD_EVENT\":\"1111\", \"STARTDATE\":\"2011-04-08T13:00:00\",\"ENDDATE\":\"2011-04-08T13:15:00\", \"TITLE\":\"222\", \"ADDRESS\":\"22\", \"DESCRIPTION\":\"22\", \"IDCALENDAR\":\"m1atghomeeuv5ttieruvrtem2s@group.calendar.google.com\", \"EMAIL\":\"casolla.alessandro@gmail.com\", \"LAT\":1, \"LNG\":1}]}");
	 *
	 * @param script
	 * @param formData
	 */
	public String execScriptPost( final Asset asset,  final MultivaluedMap<String,String> formData )  {		
		return manager.call( new JerseyCall<String>() {

			@Override
			public String exec() {
				String url = manager.getServiceUrl(SCRIPTLET_EXEC_BASEURI + AssetImpl.toKey(asset));
				
				String result = 
					manager.getClient()
						.resource(url)
						.type( MediaType.APPLICATION_FORM_URLENCODED_TYPE )
						.post(String.class, formData);				
				
				return result;
				
			}
		});
				
	}
	
	

	/**
	 * 
	 * @param script
	 * @param param
	 * @throws Exception
	 */
	public String execScriptAsyncGet( final Asset asset, final String redirectUri, final MultivaluedMap<String,String> queryData ) throws Exception {		
		if( manager.getClient() == null ) throw new IllegalStateException("service has not been initialized!!");

		queryData.add(REDIRECT_URI, redirectUri);
		
		return manager.call( new JerseyCall<String>() {

			@Override
			public String exec() {

				return  manager.getClient().resource( manager.getServiceUrl(SCRIPTLET_EXEC_BASEURI_ASYNC + AssetImpl.toKey(asset)) )
						.queryParams(queryData)
						.get(String.class);
				
			}
		});
		
	}
	
	public String execScriptAsyncPost( final Asset asset, final String redirectUri, final MultivaluedMap<String,String> formData )  {		
		
		formData.add(REDIRECT_URI, redirectUri);
		
		return manager.call( new JerseyCall<String>() {

			@Override
			public String exec() {
				String url = manager.getServiceUrl(SCRIPTLET_EXEC_BASEURI_ASYNC + AssetImpl.toKey(asset));
				
				String result = 
					manager.getClient()
						.resource(url)
						.type( MediaType.APPLICATION_FORM_URLENCODED_TYPE )
						.post(String.class, formData);				
				
				return result;
				
			}
		});
				
	}

	@Override
	public ClassLoader getCL(ScriptletAsset s) {
		return getClass().getClassLoader();
	}


}
